package com.demo.controller;

import org.redisson.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author gy
 */
@RestController
public class ProductController {

    private static final Logger logger = LoggerFactory.getLogger(ProductController.class);
    // 商品id
    private static final String PRODUCT_KEY = "product_001";
    // 商品总数量
    private static final int TOTAL_QUANTITY = 100;
    // 分区容量
    private static final int SEGMENT_QUANTITY = 25;
    // 分区数量
    private static final int SEGMENTS = TOTAL_QUANTITY / SEGMENT_QUANTITY;
    // 分区前缀
    private static final String PRODUCT_KEY_SEGMENT_PREFIX = PRODUCT_KEY + "_p";;

    // 客户端ID到分区地址的映射表
    private static final Map<String, Integer> clientToSegmentMap = new HashMap<>();

    
    // 初始化客户端ID到分区的映射表
    static {
        // 假设有一些客户端ID的列表
        String[] clientIds = {
                "client_001",
                "client_002",
                "client_003",
                "client_004",
                "client_005",
                // 添加更多的客户端ID
        };
        Integer[] segmentIds = {1,2,3,4};

        // 将客户端ID映射到分区
        for (int i = 0; i < clientIds.length; i++) {
            clientToSegmentMap.put(clientIds[i], segmentIds[i % SEGMENTS]);
        }
    }

    @Autowired
    private RedissonClient redissonClient;

    @RequestMapping(method = RequestMethod.GET,value = "/decrease/{clientId}/{quantity}")
    public boolean decreaseQuantity(@PathVariable String clientId,@PathVariable Integer quantity) {
        RLock lock = redissonClient.getLock(PRODUCT_KEY + "_lock");
        try {
            lock.lock();

            // 获取当前段 若该客户端未配置，那么属于默认分段 1
            int currentSegment = clientToSegmentMap.get(clientId) == null ? 1 : clientToSegmentMap.get(clientId);

            // 如果商品数量已经扣减完，则返回失败
            // 此处基本不可能
            if (currentSegment > SEGMENTS) {
                return false;
            }

            // 开启事务
            TransactionOptions options = TransactionOptions.defaults();
            RTransaction transaction = redissonClient.createTransaction(options);
            try {
                // todo 检查自己的分段的数值是否足够扣减
                RBucket<Integer> currentSegmentBucket = transaction.
                        getBucket(PRODUCT_KEY_SEGMENT_PREFIX + currentSegment);
                Integer currentSegmentQuantity = currentSegmentBucket.get();
                if (currentSegmentQuantity == null || currentSegmentQuantity < 0) {
                    return false;
                }
                // 自己的数量够扣减
                if (currentSegmentQuantity >= quantity){
                    currentSegmentBucket.set(currentSegmentQuantity - quantity);
                    transaction.commit();
                    logger.info("分区"+ PRODUCT_KEY_SEGMENT_PREFIX + currentSegment + "扣减"+quantity);
                    logger.info("成功下单数量为:"+quantity);
                    return true;

                }else {
                    // 检查所有分段的数量是否足够
                    int totalQuantity = 0;
                    for (int i = 1; i <= SEGMENTS; i++) {
                        String segmentKey = PRODUCT_KEY_SEGMENT_PREFIX + i;
                        RBucket<Integer> segmentBucket = transaction.getBucket(segmentKey);
                        Integer segmentQuantity = segmentBucket.get();
                        if (segmentQuantity == null || segmentQuantity < 0) {
                            return false;
                        }
                        totalQuantity += segmentQuantity;
                    }

                    // 如果所有分段的数量足够，则进行按照 顺序分段 依次扣减操作
                    if (totalQuantity >= quantity) {
                        int a = quantity;
                        logger.info("当前库存:"+totalQuantity+"下单数量为:"+quantity+" -------- 满足下单要求");
                        for (int i = 1; i <= SEGMENTS; i++) {
                            String segmentKey = PRODUCT_KEY_SEGMENT_PREFIX + i;
                            RBucket<Integer> segmentBucket = transaction.getBucket(segmentKey);
                            Integer segmentQuantity = segmentBucket.get();
                            if (segmentQuantity >= quantity) {
                                // 当前分段的数量足够扣减
                                segmentBucket.set(segmentQuantity - quantity);
                                logger.info("分区"+segmentKey + "扣减"+quantity);
                                break;
                            } else {
                                // 当前分段的数量不足，扣减当前分段的数量，继续扣减下一个分段
                                segmentBucket.set(0);
                                quantity -= segmentQuantity;
                                logger.info("分区"+segmentKey + "扣减"+segmentQuantity);
                            }
                        }
                        logger.info("成功下单数量为:"+a);
                        transaction.commit();
                        return true;

                    } else {
                        // 总数量不足，无法完成扣减，事务回滚
                        logger.info("当前库存:"+totalQuantity+"下单数量为:"+quantity+" -------- 库存不足！！！");
                        logger.info("下单失败");
                        transaction.rollback();
                        return false;
                    }
                }
            } catch (Exception e) {
                transaction.rollback();
                throw e;
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * product_001_p1: 25
     * product_001_p2: 25
     * product_001_p3: 25
     * product_001_p4: 25
     * @return
     */
    @RequestMapping("/addTestData")
    public String decreaseQuantity() {
        // 初始化每个分区的 商品数量
        for (int i = 1; i <= SEGMENTS; i++) {
            String segmentKey = PRODUCT_KEY_SEGMENT_PREFIX + i;
            RBucket<Integer> segmentBucket = redissonClient.getBucket(segmentKey);
            segmentBucket.set(SEGMENT_QUANTITY);
            logger.info("分区 "+ segmentKey +" 的数据初始化完成,为："+segmentBucket.get());
        }
        return "初始化分区数据完成";
    }


}
